package fr.uvsq.isty.bdh.hchess.engine;

import fr.uvsq.isty.bdh.hchess.util.GlobalConfig;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Singleton class with allow to create engines for the UCI.
 * 
 * @author Florent Hemmi <florent.hemmi@gmail.com>
 */
public class Engines {
    
    /** Unique instance */
    private static Engines instance = null;
    /** Current file name */
    private String currentLoadedFile;
    /** Engines list */
    private List<Engine> engines;
    
    /** Private constructor for the initialization */
    private Engines() throws IOException {
        engines = new ArrayList<Engine>();
        String toLoad = GlobalConfig.getInstance().get("engine", "path", "data/engines.db");
	load(toLoad);
    }
    
    /**
     * Call this method to retrieve the instance of the object.
     * In fact, constructor cannot be called directly.
     * 
     * @return An instance of the object (the same as before if already created)
     */
    public static Engines getInstance() throws IOException {
        if (instance == null) {
            instance = new Engines();
        }
        return instance;
    }
    
    /**
     * Save engines
     * @param fileName name file where to save
     * @throws IOException
     */
    private void save(String fileName) throws IOException {
        ObjectOutputStream output =
                new ObjectOutputStream(new FileOutputStream(fileName));
        output.writeObject(engines);
    }
    
    /**
     * Load engines.
     * @param fileName name file where to load
     * @throws IOException
     */
    private void load(String fileName) throws IOException {
    	ObjectInputStream input = null;
		File F = new File(fileName);
		F.createNewFile();
        try {
    	    input = new ObjectInputStream(new FileInputStream(fileName));
            engines = (ArrayList<Engine>) input.readObject();
            if(engines==null){
            	save(fileName);
            }
        } catch (ClassNotFoundException ex) {
        	save(fileName);
        }catch(EOFException e){
        	save(fileName);
        }
        if(input!=null){
        	input.close();
        }
        currentLoadedFile = fileName;
    }
    
    /**
     * Add an engine to the engines list and save it.
     * @param e Engine to add
     * @return true if success
     * @throws IOException 
     */
    public boolean addEngine(Engine e) throws IOException {
        boolean alreadyExist = false;
    	for(Engine curEngine : engines){
            if(curEngine.getName().equals(e.getName())){
                    alreadyExist = true;
                    break;
            }
    	}
    	if(!alreadyExist){
    		engines.add(e);
                sort();
                save(currentLoadedFile);
                return true;
    	}
        return false;
    }
    
    /**
     * Add an engine to the engines list and save it.
     * @param name engine name
     * @param path engine path
     * @return true if success
     * @throws IOException 
     */
    public boolean addEngine(String name, String path) throws IOException {
        return addEngine(new Engine(name, path));
    }
    
    /**
     * Sort alphabetically the engines list.
     * Call each time an engine is added.
     */
    private void sort() {
        List<Engine> lengines = new ArrayList<Engine>();
        List<String> lname = this.list();
        Collections.sort(lname, String.CASE_INSENSITIVE_ORDER);
        for (String s : lname) {
            lengines.add(new Engine(s, getEnginePath(s)));
        }
        this.engines = lengines;
    }
    
    /**
     * 
     * @return String list of all engines name
     */
    public List<String> list() {
        List<String> engineName = new ArrayList<String>();
        for (Engine e : engines)
            engineName.add(e.getName());
        return engineName;
    }
    
    /**
     * 
     * @param name engine name
     * @return engine path
     */
    public String getEnginePath(String name) {
        for (Engine e : engines) {
            if (e.getName().equals(name))
                return e.getPath();
        }
        return null;
    }
    
    /**
     * Delete an engine
     * 
     * @param name engine name
     * @return true if deleted successfully
     * @throws IOException 
     */
    public boolean deleteEngine(String name) throws IOException {
        boolean found = false;
        int i;
        for (i=0; i<engines.size(); i++) {
            if (engines.get(i).getName().equals(name)) {
                found = true;
                break;
            }
        }
        if (found) {
            engines.remove(i);
            save(currentLoadedFile);
            return true;
        }
        return false;
    }
    
    /**
     * 
     * @return number of engines installed
     */
    public int getNbEngineInstalled() {
        return engines.size();
    }
}
